//
// server.cpp
// ~~~~~~~~~~

#include "server.hpp"
#include <boost/bind.hpp>

namespace http {
    namespace server3{

        int server::request_rate = 0;
        int server::cache_size = 100000000;
        long server::cache_hit=0;
        long server::cache_miss=0;
        long server::processed_zc1 = 0;
        long server::received_zc1 = 0;
        long server::parsing_error = 0;
        int  server::unknown_ip=0;
        int  server::total_request = 0;
        int  server::error_request = 0;
        std::map<std::string, int> server::business_count_map;
        boost::mutex server::map_mutex;
        std::string server::log_time = currentDateTime();

    	std::string server::start_time = "";
        //initializing caching
        boost::shared_ptr<server::lru_cache> server::mobile_cache_ptr_;

        server::server(const std::string& address, const std::string& port, std::size_t io_service_pool_size)
            : io_service_pool_(io_service_pool_size),
            signals_(io_service_pool_.get_io_handler().first),
            acceptor_(io_service_pool_.get_io_handler().first),
            new_connection_(),
            rate_timer_(io_service_pool_.get_io_handler().first, boost::posix_time::seconds(2)),
            last_request_num(0),
            refresh_rate_timeout(1)
        {
            // Register to handle the signals that indicate when the server should exit.
            // It is safe to register for the same signal multiple times in a program,
            // provided all registration for the specified signal is made through Asio.

            signals_.add(SIGINT);
            signals_.add(SIGTERM);
#if defined(SIGQUIT)
            signals_.add(SIGQUIT);
#endif // defined(SIGQUIT)
            signals_.async_wait(boost::bind(&server::handle_stop, this));

            // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
            boost::asio::ip::tcp::resolver resolver(acceptor_.get_io_service());
            boost::asio::ip::tcp::resolver::query query(address, port);
            boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
            acceptor_.open(endpoint.protocol());
            acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
            acceptor_.bind(endpoint);
            acceptor_.listen();

            rate_timer_.async_wait(boost::bind(&server::calculate_rate, this));

            //Initializing caching mobile service data
            mobile_cache_ptr_.reset(new lru_cache(server::cache_size));

            start_accept();
        }

        void server::run()
        {
        	server::start_time = currentDateTime();
            io_service_pool_.run();
        }

        void server::start_accept()
        {
            io_service_pool::io_handler_pair io = io_service_pool_.get_io_handler();
            new_connection_.reset(new connection(
                io.first.get(), io.second.get()));

            acceptor_.async_accept(new_connection_->socket(),
                boost::bind(&server::handle_accept, this,
                boost::asio::placeholders::error));
        }

        void server::handle_accept(const boost::system::error_code& e)
        {
            if (!e)
            {
                new_connection_->start();
            }

            start_accept();
        }

        void server::calculate_rate()
        {
               server::request_rate = (connection::request_num - server::last_request_num)/refresh_rate_timeout;
               server::last_request_num = connection::request_num;
               //std::cout <<"\nRate = " << server::request_rate;
               rate_timer_.expires_at(rate_timer_.expires_at() + boost::posix_time::seconds(refresh_rate_timeout));
               rate_timer_.async_wait(boost::bind(&server::calculate_rate, this));
        }

        // Get current date/time, format is YYYY-MM-DD.HH:mm:ss
        std::string server::currentDateTime() {
            time_t     now = time(0);
            struct tm  tstruct;
            char       buf[80];
            tstruct = *localtime(&now);
            // Visit http://www.cplusplus.com/reference/clibrary/ctime/strftime/
            // for more information about date/time format
            strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
            return buf;
        }

        void server::handle_stop()
        {
            io_service_pool_.stop();
        }

    } // namespace server2
} // namespace http
